package com.vast.admin.utils;

import com.vast.admin.entity.RepaymentPlanWord;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 等额本息还款，也称定期付息，即借款人每月按相等的金额偿还贷款本息，其中每月贷款利息按月初剩余贷款本金计算并逐月结清。把按揭贷款的本金总额与利息总额相加，
 * 然后平均分摊到还款期限的每个月中。作为还款人，每个月还给银行固定金额，但每月还款额中的本金比重逐月递增、利息比重逐月递减。
 */

public class AverageCapitalPlusInterestUtils {

    /**
     * 计算方式 四舍五入
     */
    private static final int CAL_METHOD = BigDecimal.ROUND_HALF_UP;

    /**
     * 等额本息计算获取还款方式为等额本息的每月偿还本金和利息
     *
     * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
     *
     * @param invest
     *            总借款额（贷款本金）
     * @param monthRate
     *            月利率
     * @param totalmonth
     *            还款总月数
     * @return 每月偿还本金和利息,不四舍五入，直接截取小数点最后两位
     */
    private static double getPerMonthPrincipalInterest(double invest, double monthRate, int totalmonth) {
        BigDecimal monthIncome = new BigDecimal(invest)
                .multiply(new BigDecimal(monthRate * Math.pow(1 + monthRate, totalmonth)))
                .divide(new BigDecimal(Math.pow(1 + monthRate, totalmonth) - 1), 2, CAL_METHOD);
        return monthIncome.doubleValue();
    }

    /**
     * 等额本息计算获取还款方式为等额本息的每月偿还利息
     *
     * 公式：每月偿还利息=贷款本金×月利率×〔(1+月利率)^还款月数-(1+月利率)^(还款月序号-1)〕÷〔(1+月利率)^还款月数-1〕
     * @param invest
     *            总借款额（贷款本金）
     * @param monthRate
     *            月利率
     * @param totalmonth
     *            还款总月数
     * @return 每月偿还利息
     */
    private static Map<Integer, BigDecimal> getPerMonthInterest(double invest, double monthRate, int totalmonth) {
        Map<Integer, BigDecimal> map = new HashMap<Integer, BigDecimal>();
        BigDecimal monthInterest;
        for (int i = 1; i < totalmonth + 1; i++) {
            BigDecimal multiply = new BigDecimal(invest).multiply(new BigDecimal(monthRate));
            BigDecimal sub  = new BigDecimal(Math.pow(1 + monthRate, totalmonth)).subtract(new BigDecimal(Math.pow(1 + monthRate, i-1)));
            monthInterest = multiply.multiply(sub).divide(new BigDecimal(Math.pow(1 + monthRate, totalmonth) - 1), 6, BigDecimal.ROUND_DOWN);
            monthInterest = monthInterest.setScale(2, BigDecimal.ROUND_DOWN);
            map.put(i, monthInterest);
        }
        return map;
    }

    /**
     * 等额本息计算获取还款方式为等额本息的每月偿还本金
     *
     * @param invest
     *            总借款额（贷款本金）
     * @param monthRate
     *            月利率
     * @param totalmonth
     *            还款总月数
     * @return 每月偿还本金
     */
    private static Map<Integer, BigDecimal> getPerMonthPrincipal(double invest, double monthRate, int totalmonth) {
        BigDecimal monthIncome = new BigDecimal(invest)
                .multiply(new BigDecimal(monthRate * Math.pow(1 + monthRate, totalmonth)))
                .divide(new BigDecimal(Math.pow(1 + monthRate, totalmonth) - 1), 2, BigDecimal.ROUND_DOWN);
        Map<Integer, BigDecimal> mapInterest = getPerMonthInterest(invest, monthRate, totalmonth);
        Map<Integer, BigDecimal> mapPrincipal = new HashMap<Integer, BigDecimal>();

        for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
            mapPrincipal.put(entry.getKey(), monthIncome.subtract(entry.getValue()));
        }
        return mapPrincipal;
    }

    /**
     * 等额本息计算获取还款方式为等额本息的总利息
     *
     * @param invest
     *            总借款额（贷款本金）
     * @param monthRate
     *            月利率
     * @param totalmonth
     *            还款总月数
     * @return 总利息
     */
    private static double getInterestCount(double invest, double monthRate, int totalmonth) {
        BigDecimal count = new BigDecimal(0);
        Map<Integer, BigDecimal> mapInterest = getPerMonthInterest(invest, monthRate, totalmonth);

        for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
            count = count.add(entry.getValue());
        }
        return count.doubleValue();
    }

    /**
     * 应还本金总和
     * @param invest
     *            总借款额（贷款本金）
     * @param monthRate
     *            月利率
     * @param totalmonth
     *            还款总月数
     * @return 应还本金总和
     */
    private static double getPrincipalInterestCount(double invest, double monthRate, int totalmonth) {
        BigDecimal perMonthInterest = new BigDecimal(invest)
                .multiply(new BigDecimal(monthRate * Math.pow(1 + monthRate, totalmonth)))
                .divide(new BigDecimal(Math.pow(1 + monthRate, totalmonth) - 1), 2, CAL_METHOD);
        BigDecimal count = perMonthInterest.multiply(new BigDecimal(totalmonth));
        count = count.setScale(2, CAL_METHOD);
        return count.doubleValue();
    }

    /**
     * 计算等额本息还款计划
     * @param invest 借款总金额
     * @param monthRate 月利率
     * @param totalMonth 还款期数
     * @param dateStr 还款日期集合
     * @return
     */
    public static List<RepaymentPlanWord> cal(double invest, double monthRate, int totalMonth, List<String> dateStr) {
        //每月还款本息合计
        double perMonthPrincipalInterest = getPerMonthPrincipalInterest(invest, monthRate, totalMonth);
        //每月还款利息
        Map<Integer, BigDecimal> mapInterest = getPerMonthInterest(invest, monthRate, totalMonth);
        //每月还款本金
        Map<Integer, BigDecimal> mapPrincipal = getPerMonthPrincipal(invest, monthRate, totalMonth);
        List<RepaymentPlanWord> repaymentPlanWords = new ArrayList<>(totalMonth);
        for (int i = 1; i <= totalMonth; i ++) {
            RepaymentPlanWord repaymentPlanWord = new RepaymentPlanWord();
            repaymentPlanWord.setRepaymentIndex(String.valueOf(i));
            repaymentPlanWord.setRepaymentDate(dateStr.get(i - 1));
            repaymentPlanWord.setTotal(String.valueOf(perMonthPrincipalInterest));
            repaymentPlanWord.setPrincipal(String.valueOf(mapPrincipal.get(i).doubleValue()));
            repaymentPlanWord.setInterest(String.valueOf(mapInterest.get(i).doubleValue()));
            repaymentPlanWords.add(repaymentPlanWord);
        }
        return repaymentPlanWords;
    }

//    public static void main(String[] args) {
//        double invest = 20000; // 本金
//        int month = 12;
//        double yearRate = 0.01; // 月利率
//        double perMonthPrincipalInterest = getPerMonthPrincipalInterest(invest, yearRate, month);
//        System.out.println("等额本息---每月还款本息：" + perMonthPrincipalInterest);
//        Map<Integer, BigDecimal> mapInterest = getPerMonthInterest(invest, yearRate, month);
//        System.out.println("等额本息---每月还款利息：" + mapInterest);
//        Map<Integer, BigDecimal> mapPrincipal = getPerMonthPrincipal(invest, yearRate, month);
//        System.out.println("等额本息---每月还款本金：" + mapPrincipal);
//        double count = getInterestCount(invest, yearRate, month);
//        System.out.println("等额本息---总利息：" + count);
//        double principalInterestCount = getPrincipalInterestCount(invest, yearRate, month);
//        System.out.println("等额本息---应还本息总和：" + principalInterestCount);
//    }
}
